/*
 * File     : JavaFunctionPointer.java
 * Created  : 15 May 2011
 *
 * Copyright © 2011 Matthew Wilson (mj. {my-surname} .uk {at} gmail.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.googlecode.dni.internal.callback;

import com.googlecode.dni.library.CallingConvention;

/**
 * Encapsulates a function pointer to a native function, with the only
 * difference being that the thunk has to be freed explicitly.
 *
 * @param <T>
 *            the delegate type
 *
 * @author Matthew Wilson
 */
final class JavaFunctionPointer< T > extends AbstractFunctionPointer< T >
{

    private boolean freed;

    /**
     * @param address
     *            the address of the thunk
     * @param delegate
     *            the delegate
     * @param callingConvention
     *            the calling convention
     */
    JavaFunctionPointer( final long address,
                         final T delegate,
                         final CallingConvention callingConvention )
    {
        super( address, delegate, callingConvention );
    }

    /** {@inheritDoc} */
    @Override
    public void free()
    {
        // locking ThunkManager is OK since ThunkManager.free will do just the
        // same in a moment
        ThunkManager manager = ThunkManager.getInstance( getCallingConvention() );
        synchronized ( manager )
        {
            if ( !this.freed )
            {
                this.freed = true;
                manager.free( this.address, getDelegate() );
            }
        }
    }

}
